#ifndef _LBWRAPPER_H_
#define _LBWRAPPER_H_

#include "../../../vedo/src/NJR/Interfaces/vector3d.h"
#include "../../../vedo/src/FrameWork/Interfaces/Boundary.h"

#include "olb3D.h"
#ifndef OLB_PRECOMPILED // Unless precompiled version is used,
  #include "olb3D.hh"   // include full template code
#endif

#include <vector>
#include <fstream>
#include <string>
#include <cmath>
#include <map>

#include "LBWrapper.hh"
#include "InteractionCalculator_Lin.hpp"
#include "BoundaryType.h"

using namespace olb;
using namespace olb::descriptors;
using namespace olb::graphics;
using namespace std;

typedef double T;

template<typename T, template<typename U> class Lattice>
class LBMBase
{
public:
	virtual ~LBMBase();
	
	virtual void InitialLattice(T nx, T ny, T nz);
	
	virtual void InitialBC();

	virtual void ApplyNeumannBoundaryConditions();

	virtual void ApplySphereCynliderBC(T cRadius, T drift);

public:
	#ifndef PARALLEL_MODE_MPI  // sequential program execution
		BlockLattice3D<T, Lattice>* lattice;
	#else                      // parallel program execution
		MultiBlockLattice3D<T, Lattice>* lattice;
	#endif	
	OnLatticeBoundaryCondition3D<T, Lattice>* boundaryCondition;
};

////////////////////////////////////////// IBMLin //////////////////////////////////////////
class IBMLin : public LBMBase<T, D3Q15Descriptor>
{
public:
	IBMLin();
	
	virtual ~IBMLin();
	
	virtual void InitialDynamics_BC_Geom(T omega, sMathLib::VectorX<int, 3> domain, BoundaryInput<T>& bInput);
	
	virtual void PrepareToCalculateInteraction(double externalForce[3]);
	
	virtual void PrepareToCalculateInteraction();
	
	virtual void ClearAllSphere();
	
	virtual void AddSphereImpl(const NJRvector3d& pos, const NJRvector3d& vel, const NJRvector3d& aVel, double r, double rotateMatrix[3][3]);

	virtual void CalculateSphereFluidInteraction(T LatticeNu, int iT);

	virtual void PrepareToNextStep();
	
	virtual T getVolumeFraction(int iX, int iY, int iZ, int np);

	virtual void recordFluidEffect(int iT, int recordStep, std::vector<T>& scalingFactor);

protected:

	InteractionCalculator_Lin<T> intCalu;
	
	BGKdynamics<T, D3Q15Descriptor>* bulkDynamics;
};
////////////////////////////////////////// IBMLin //////////////////////////////////////////

////////////////////////////////////////// IBM2008 //////////////////////////////////////////
class IBM2008 : public LBMBase<T, ForcedD3Q15Descriptor>
{

};
////////////////////////////////////////// IBM2008 //////////////////////////////////////////

////////////////////////////////////////// LBWrapper //////////////////////////////////////////
template <class IBMPolicy>
class LBWrapper : public IBMPolicy
{
public:
	LBWrapper(int argc, char* argv[], sMathLib::VectorX<int, 3> N_, double tau, const string& dir, T vtkLogStep, BoundaryInput<T>& bInput);
	virtual ~LBWrapper();

public:
	
	void SetPeriodicBoundaryConditions(const Boundary* pbc);
	
	void AddSphere(const NJRvector3d& pos, const NJRvector3d& vel, const NJRvector3d& aVel, double r, double rotateMatrix[3][3]);
	
	int GetNumberOfSphere() const;
	
	const NJRvector3d& GetSphereForces(int i);
	
	const NJRvector3d& GetSphereTorque(int i);
	
	void ModifyBCVelocity(T base_vel);
		
	void NextStep();	
	void NextStep(int iT, ibm::LBMUnit<int, T>* cu);
	
	//void ApplyBoundaries();

	void DrawField(int iT, int interval, ibm::LBMUnit<int, T>* cu);
	
	void AssignBottomPressure(T pre);

	int iT;

private:
	
private:
	
	T _vtkSave;
	T _tau;
	T _omega;
	
	sMathLib::VectorX<int, 3> _domain;
	T _pressure;
	
	bool LBM_periodic;
	
	T cCylinderRadius_;

	const Boundary* pbc;
	
	
};
////////////////////////////////////////// LBWrapper //////////////////////////////////////////
	

#endif /*LBWRAPPER_H_*/
